package com.itheima.aop;


import com.alibaba.fastjson.JSON;
import com.itheima.pojo.OperateLog;
import com.itheima.mapper.OperateLogMapper;
import com.itheima.utils.CurrentHolder;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Currency;
import java.util.HashSet;
import java.util.Set;

/**
 * 操作日志切面
 */
@Slf4j
@Aspect
@Component
public class OperateLogAspect {
    private static final int MAX_PARAM_LENGTH = 2000;
    private static final String VOID_RETURN = "void";
    private static final Integer DEFAULT_USER_ID = 0;
    private static final Set<Class<?>> UNSERIALIZABLE_CLASSES = new HashSet<>(Arrays.asList(
            jakarta.servlet.http.HttpServletRequest.class,
            jakarta.servlet.http.HttpServletResponse.class,
            jakarta.servlet.http.HttpSession.class,
            org.springframework.web.multipart.MultipartFile.class
    ));

    @Autowired
    private OperateLogMapper operateLogMapper;

    /**
     * 定义切点：拦截com.itheima.controller包下所有类的所有方法
     */
    @Pointcut("@annotation(com.itheima.anno.LogOperation)")
    public void operateLogPointCut() {}

    /**
     * 环绕通知：记录操作日志
     */
    @Around("operateLogPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 记录开始时间
        long startTime = System.currentTimeMillis();
        
        // 执行目标方法
        Object result = null;
        Throwable exception = null;
        
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            exception = e;
            throw e;
        } finally {
            // 记录结束时间
            long endTime = System.currentTimeMillis();
            long costTime = endTime - startTime;
            
            // 记录日志（无论方法是否抛出异常都记录）
            try {
                // 保存操作日志
                saveOperateLog(joinPoint, result, costTime, exception);
            } catch (Exception logException) {
                // 日志记录失败不应影响主要业务逻辑
                logException.printStackTrace();
            }
        }
        
        return result;
    }

    /**
     * 保存操作日志
     */
    private void saveOperateLog(ProceedingJoinPoint joinPoint, Object result, long costTime, Throwable exception) {
        OperateLog operateLog = new OperateLog();
        
        // 设置操作时间
        operateLog.setOperateTime(LocalDateTime.now());
        
        // 设置操作人ID（这里需要根据你的认证系统获取当前用户ID）
        // 假设从Session或JWT Token中获取用户ID
        Integer currentUserId = getCurrentUserId();
        operateLog.setOperateEmpId(currentUserId);
        
        // 获取目标类名和方法名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = joinPoint.getTarget().getClass();
        
        operateLog.setClassName(targetClass.getName());
        operateLog.setMethodName(method.getName());
        
        // 设置方法参数（JSON格式）
        Object[] args = joinPoint.getArgs();
        // 过滤掉HttpServletRequest和HttpServletResponse等无法序列化的参数
        String methodParams = Arrays.stream(args)
                .filter(arg -> !isUnserializableObject(arg))
                .map(JSON::toJSONString)
                .reduce((a, b) -> a + ", " + b)
                .orElse("");
        operateLog.setMethodParams(methodParams.length() > MAX_PARAM_LENGTH ? 
                methodParams.substring(0, MAX_PARAM_LENGTH) : methodParams);
        
        // 设置返回值（JSON格式）
        if (result != null) {
            String returnValue = JSON.toJSONString(result);
            operateLog.setReturnValue(returnValue.length() > MAX_PARAM_LENGTH ? 
                    returnValue.substring(0, MAX_PARAM_LENGTH) : returnValue);
        } else {
            operateLog.setReturnValue(VOID_RETURN);
        }
        
        // 设置执行耗时
        operateLog.setCostTime(costTime);

        log.info("日志记录:{}",operateLog);

        // 保存到数据库
        operateLogMapper.insert(operateLog);
    }

    /**
     * 获取当前用户ID（需要根据你的认证系统实现）
     */
    private Integer getCurrentUserId() {
        return CurrentHolder.getCurrentId();
    }

    /**
     * 判断对象是否不可序列化
     */
    private boolean isUnserializableObject(Object obj) {
        if (obj == null) {
            return true;
        }
        // 常见的不可序列化对象类型
        return UNSERIALIZABLE_CLASSES.contains(obj.getClass());
    }
}